<template>
  <el-dialog
    top="50px"
    width="800px"
    :title="title"
    append-to-body
    class="dialog-sm"
    :close-on-click-modal="false"
    :visible.sync="visible"
    :before-close="beforeClose"
  >
    <div
      class="attach-upload-container"
      :class="{ 'is-dragover': dragover }"
      v-loading="getLoading"
      @drop.prevent="onDrop"
      @dragover.prevent="onDragover"
      @dragleave.prevent="dragover = false"
    >
      <div class="row">
        <div class="col-3" v-for="(file, index) in list" :key="file.id">
          <attach-upload-item
            :loading="loading"
            :file="file"
            :view-mode="viewMode"
            @delete="handleDeleteAttach"
          >
            <el-button
              slot="viewAction"
              round
              icon="el-icon-zoom-in"
              @click="handlePreviewFile(index)"
            ></el-button>
          </attach-upload-item>
        </div>

        <div class="col-3" v-if="!viewMode">
          <div class="attach-upload-item">
            <input
              type="file"
              ref="uploadInput"
              class="d-none"
              multiple
              :accept="mineTypes"
              @change="handleFileChange"
            />
            <el-button class="attach-upload-btn" :disabled="loading" @click="handleSelectFile">
              <i class="el-icon-upload attach-upload-btn-icon"></i>
              <div class="attach-upload-btn-text">点击上传</div>
              <div class="text-muted">或将文件拖到此处</div>
            </el-button>
          </div>
        </div>
      </div>
    </div>
  </el-dialog>
</template>

<script>
import { uploadOss, deleteOss } from '@/common/api/oss'
import { mineTypeMap } from '@/common/api/download'
import { getFileType, revokeObjectURL } from '@/common/plugins/tools/file'
import { attachAdapter, fileAdapter } from '@/bank/components/attach/index'

import AttachUploadItem from '@/credit/views/city/bus/normal/invest/AttachUploadItem'

const noop = () => {}

export default {
  components: {
    AttachUploadItem,
  },
  props: {
    visible: Boolean,
    title: {
      type: String,
      default: '附件',
    },
    relatedId: String,
    viewMode: Boolean,
    attachTag: String,
    parentTag: String,
    fileTypes: {
      type: Array,
      default: () => ['png', 'jpeg', 'jpg', 'bmp', 'gif'],
    },
    beforeUpload: {
      type: Function,
      default: noop,
    },
  },
  data() {
    return {
      loading: false,
      getLoading: false,
      tableName: 'datum_customer_attachment',
      list: [],
      uploadFiles: [],
      dragover: false,
    }
  },
  computed: {
    mineTypes() {
      return this.fileTypes.map(type => mineTypeMap.get(type) || type).join(',')
    },
    fileTypesLabel() {
      return '上传文件支持格式:' + this.fileTypes.join(';')
    },
    fileCount() {
      return this.uploadFiles.length
    },
  },
  watch: {
    visible: {
      handler: function () {
        if (this.visible) {
          this.getData(false)
        }
      },
      immediate: true,
    },
  },
  created() {},
  mounted() {},
  methods: {
    handlePreviewFile(index) {
      this.$utils.viewer({
        images: this.list,
        index,
      })
    },
    beforeClose() {
      this.reset()
      this.$emit('update:visible', false)
    },
    getData(emit = true) {
      if (!this.relatedId || this.getLoading) return
      this.getLoading = true
      this.$api
        .getData({
          table: this.tableName,
          params: {
            'customer_related_id.eq': this.relatedId,
          },
          order: {
            create_time: 'desc',
          },
        })
        .then(res => {
          this.list = []
          const data = res.data || []
          for (const item of data) {
            if (this.attachTag && item.attachment_type !== this.attachTag) continue
            this.list.push(attachAdapter(item))
          }
          this.$emit('after-data', { list: data, emit })
        })
        .finally(() => {
          this.getLoading = false
        })
    },

    reset() {
      this.uploadFiles.forEach(file => {
        revokeObjectURL(file.url)
      })
      this.uploadFiles = []

      const { uploadInput } = this.$refs
      if (uploadInput) {
        uploadInput.value = ''
      }
    },

    handleSelectFile() {
      if (!this.relatedId) {
        return this.$message.error('没有项目附件的相关信息，不能上传附件')
      }

      const { uploadInput } = this.$refs
      uploadInput.click()
    },

    handleFileChange(e) {
      const { files = [] } = e.target

      for (let i = 0; i < files.length; i++) {
        this.uploadFiles.push(fileAdapter(files[i]))
      }

      this.handleUploadFile()
      this.handleClear()
    },
    handleClear() {
      const { uploadInput } = this.$refs
      uploadInput.value = ''
    },

    // 删除本地file
    handleDeleteFile(index) {
      this.uploadFiles.splice(index, 1)
    },
    // 删除附件
    handleDeleteAttach(attach) {
      const { attachment: url, id } = attach
      this.$utils
        .msgbox({
          message: '确定删除此附件?',
          beforeClose: () => this.deleteData(id),
        })
        .then(() => {
          deleteOss(url)
          this.$message.success('删除成功！')
          this.getData(true)
          this.$emit('delete', attach)
        })
        .catch(err => {
          this.$message.error('删除失败，请重试！')
          throw new Error(err)
        })
    },
    deleteData(id) {
      return this.$api.deleteData(this.$serviceName, this.tableName, id)
    },

    // 上传OSS
    async handleUploadFile() {
      const { fileCount, uploadFiles } = this

      if (fileCount === 0) {
        return this.$message.error('请先选择文件')
      }

      // 上传前
      let bu = this.beforeUpload()
      if (bu && bu.then) {
        bu = await bu.then()
      }
      if (bu === false) {
        return
      }

      const promises = uploadFiles.map(it =>
        uploadOss({
          file: it.file,
          dir: `credit/attach/${this.relatedId}`,
          type: 1,
          progress: ({ percent }) => {
            it.percent = percent
            it.loading = percent < 100
          },
        })
      )

      this.loading = true
      return Promise.all(promises)
        .then(list => {
          const attachData = list.map((url, index) => {
            const { viewType, name } = uploadFiles[index]
            return {
              attachment: url,
              parent_attachment_type: this.parentTag,
              attachment_type: this.attachTag,
              customer_related_id: this.relatedId,
              file_type: viewType === 'image' ? 1 : 2,
              remark: name,
            }
          })
          return this.addData(attachData).then(res => ({ res, list }))
        })
        .then(res => {
          this.getData()
          this.reset()
          this.$emit('success', res)
        })
        .catch(err => {
          this.$message.error(err?.errorMessage ?? '上传失败')
        })
        .finally(() => {
          this.loading = false
        })
    },

    // 添加附件表
    async addData(data) {
      return this.$api.addBatch('credit', this.tableName, data)
    },

    // 拖拽上传
    onDragover() {
      if (!this.loading) {
        this.dragover = true
      }
    },

    // 拖拽放下
    onDrop(e) {
      if (this.loading) return
      this.dragover = false

      const { files } = e.dataTransfer
      for (let i = 0; i < files.length; i++) {
        const file = files[i]
        // 过滤类型
        if (this.fileTypes.includes(getFileType(file.name))) {
          this.uploadFiles.push(fileAdapter(file))
        }
      }

      this.handleUploadFile()
    },
  },
}
</script>

<style lang="scss" scoped>
.text-sm {
  font-size: 0.875rem;
}

.attach-upload-item {
  position: relative;
  overflow: hidden;
  height: 136px;
  margin: 0.5rem 0;
  border: 1px solid $gray-200;
  border-radius: 0.25rem;

  &.disabled {
    cursor: not-allowed;
  }
}

.attach-upload-container {
  width: 100%;
  height: 50vh;
  overflow-y: auto;
  padding-top: 0.5rem;
  padding: 0.5rem;
  padding-left: $grid-gutter-width;
  padding-right: $grid-gutter-width;
  transition: background-color 0.1s;
  border: 1px solid $border-color;

  @include scrollbar-theme();

  &.is-dragover {
    background-color: $primary-light-9;
    background-color: var(--primary-light-9);

    /deep/ .attach-upload-item .el-button {
      background-color: $primary-light-9;
      background-color: var(--primary-light-9);
    }
  }
}

.attach-upload-btn {
  width: 100%;
  height: 100%;
  border-radius: 0.1rem;
  border: none;
  color: $primary;
  color: var(--primary);

  &-icon {
    font-size: 4rem;
    color: $gray-500;
    margin-bottom: 0.5rem;
  }

  &:disabled {
    color: $gray-500;
    cursor: not-allowed;
  }
}
</style>
